package com.rpframework.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 类相关工具类
 * Created by jump on 2016/7/7.
 */
public class ClassUtils {
    /**
     * 获取字段值
     *
     * @param <T>          属性值类型
     * @param object       字节码
     * @param field        字段名
     * @param requiredType 返回参数类型
     * @return 值 为空有返回NULL
     */
    public static <T> T getFieldValue(Object object, String field, Class<T> requiredType) {
        Class<?> clazz = object.getClass();
        Field basePackage = getField(clazz, field);
        Object o;
        try {
            assert basePackage != null;
            basePackage.setAccessible(true);
            o = basePackage.get(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        if (o != null) {
            if (requiredType != null && !requiredType.isInstance(o)) {
                throw new RuntimeException("类型不匹配");
            }
            return (T) o;
        }
        return null;
    }


    /**
     * 获取字段
     *
     * @param clazz     字节码
     * @param fieldName 字段名
     */
    private static Field getField(Class<?> clazz, String fieldName) {
        Field[] fields = clazz.getFields();
        Field[] declaredFields = clazz.getDeclaredFields();
        fields = ArrayUtils.concatAll(fields, declaredFields);
        for (Field field :
                fields) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }
        Class<?> superClass = clazz.getSuperclass();
        if (superClass != null && !superClass.equals(Object.class)) {
            return getField(superClass, fieldName);
        }
        return null;
    }

    /**
     * 获取get方法字段名
     *
     * @param method 方法
     * @return 字段名
     */
    static String getDeclaredField(Method method) {
        String name = method.getName();
        if (name.startsWith("get")) {
            String f = name.substring(3);
            return f.substring(0, 1).toLowerCase() + f.substring(1);
        }
        return null;
    }

    /**
     * 通过反射, 获得定义Class时声明的父类的泛型参数的类型. 如无法找到, 返回Object.class.
     *
     * @param clazz 类的实例
     * @param index 通用声明的索引，从0开始。
     * @return 指数泛型声明，或Object.class如果不能确定
     */
    public static Class<?> getSuperClassGenericType(final Class clazz, final int index) {

        //返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的直接超类的 Type。
        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            return Object.class;
        }
        //返回表示此类型实际类型参数的 Type 对象的数组。
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            return Object.class;
        }

        return (Class) params[index];
    }
}
